// ParticleForceGenerators and Registry

// Provide a convenient mechanism to create all kinds of
// variety of forces. Uses polymorphism and an STL vector
// to keep track of all forces and iterate through them,
// applying them to our Particle objects (which is also
// a base class)
#pragma once

#include "core.h"
#include "particle.h"
#include <vector>

namespace physics {
	///////////////////////////////////////////
	// ParticleForceGenerator
	///////////////////////////////////////////
	// Can be used to apply forces to Particle objects (and objects which inherit from it)
	// Abstract base class, which other classes must inherit from
	class ParticleForceGenerator
	{
	public:
		// Needs to be overloaded by the child object to determine how the force changes over time
		virtual void updateForce(Particle *particle, real dt) = 0;
	};


	///////////////////////////////////////////
	// ParticleGravity
	///////////////////////////////////////////
	// Generates an acceleration that simulates gravity on the particle
	// i.e. always applies, and always points in the -y direction
    class ParticleGravity : public ParticleForceGenerator
    {
	private:
        // holds the gravity vector
        Vector3 gravity;

    public:

        // creates the gravity vector
        ParticleGravity(const Vector3 &gravity);

        // applies the force to the particle using the passed duration
        virtual void updateForce(Particle *particle, real dt);
    };


	///////////////////////////////////////////
	// ParticleDrag
	///////////////////////////////////////////
	// creates a drag force on the given particle
	class ParticleDrag : public ParticleForceGenerator
	{
	private:
		// holds the first-order coefficient ( k1 * v )
		real k1;

		// holds the second-order coefficient (k2 * v * v)
		real k2;

	public:
		// creates the PFG and stores the data
		ParticleDrag(real k1, real k2);
		// applies the force to the particle
		virtual void updateForce(Particle *particle, real dt);
	};




	///////////////////////////////////////////
	// ParticleForceRegistry
	///////////////////////////////////////////
	// keeps track of all of the forces being applied to
	// every object so we can iterate through them
	class ParticleForceRegistry
	{
	protected:
		struct ParticleForceRegistration
		{
			Particle *particle; // the particle having a force applied to it
			ParticleForceGenerator *pfg; // the force generator being applied to the particle
		};

		// for tidier code
		typedef std::vector<ParticleForceRegistration> Registry;
		
		// STL vector object that keeps track of all force generators
		// and their respective particles
		Registry forceGenerators;
	public:
		// adds a PFG to the list
		void add(Particle *particle, ParticleForceGenerator *pfg);
		// removes a PFG from the list
		void remove(Particle *particle, ParticleForceGenerator *pfg);
		// removes all PFGs
		void clear();
		// tells all force generators to update their corresponding particles
		void updateForces(real dt);
	};
}